package com.ease.framework.priv {

   import com.ease.util.ReflectionUtil;

   import flash.events.Event;
   import flash.utils.Dictionary;

   /**
    * @private
    *
    * Holds information about a response (as in a request-response pattern).
    *
    * <p>The response object itself is not referenced here due to the same reason as request
    * is not referenced by RequestInfo.
    */
   public class ResponseInfo
   {
      /**
       * The entity that made the original request whose response is represented by this info
       * object.
       */
      public var requestor:Object;

      /** The associated request may not be known. */
      [Optional]
      /**
       * The request that resulted in this response, where both request and response are
       * typically <code>Event</code>s.
       */
      public var request:Object;

      [Optional]
      public var result:Object;

      [Optional]
      public var error:Error;

      [Optional]
      public var resultInfo:Object;

      /**
       * Indicates that the error contained in this object, if any, was delivered to some
       * error handler.
       */
      public var wasErrorDelivered:Boolean = false;

      /**
       * Initializes a new instance of this class using the properties of the given response
       * object that are tagged as [Request], [RequestSource], [Result], [Error] and
       * [ResultInfo].
       */
      public static function fromResponse( response:Object,
                                           request:Object = null ):ResponseInfo {
         var info:ResponseInfo = new ResponseInfo();
         if (request != null) {
            info.request = request;
         } else {
            info.request = ReflectionUtil.getTaggedPropertyValue(
               response, "InjectableRequest|Request" );
         }
         if (info.request is Event) {
            info.requestor = Event( info.request ).target;
         } else {
            info.requestor =
               ReflectionUtil.getTaggedPropertyValue( response, "RequestSource" );
         }
         info.result =
            ReflectionUtil.getTaggedPropertyValue( response, "Result|InjectableResult" );
         info.error = ReflectionUtil.getTaggedPropertyValue(
            response, "Error|InjectableError" ) as Error;
         info.resultInfo = ReflectionUtil.getTaggedPropertyValue( response, "ResultInfo" );
         return info;
      }

      /**
       * Updates the given response and ResponseInfo objects using the provided request.
       */
      public static function setRequestOnResponse( request:Object, response:Object,
                                                   responseInfo:ResponseInfo ):void {
         ReflectionUtil.setTaggedPropertyValue(
            response, "InjectableRequest|Request", request );
         responseInfo.request = request;
         if (!(request is Event)) {
            return;
         }
         var requestor:Object = Event( request ).target;
         ReflectionUtil.setTaggedPropertyValue( response, "RequestSource", requestor );
         responseInfo.requestor = requestor;
      }

      /**
       * Sets the given objects as the values of certain tagged properties of the given
       * response object.
       */
      public static function setTaggedPropertiesOnResponse(
         response:Event, request:Object, result:Object, error:Error ):void {
         // [Result] and [InjectableResult] are equivalent
         ReflectionUtil.setTaggedPropertyValue( response, "InjectableResult|Result",
            result );
         // [Error] and [InjectableError] are equivalent
         ReflectionUtil.setTaggedPropertyValue( response, "InjectableError|Error", error );
         // [Request] and [InjectableRequest] are equivalent
         ReflectionUtil.setTaggedPropertyValue( response, "InjectableRequest|Request",
            request );
         if (request is Event) {
            ReflectionUtil.setTaggedPropertyValue( response, "RequestSource",
               Event( request ).target );
         }
      }

      /**
       * Indicates whether the given object contains non-null information about some request,
       * i.e., if it has either a [Request] or a [RequestSource] property and at least one of
       * them is set.
       */
      public static function carriesRequestInfo( object:Object ):Boolean {
         var propVal:Object = ReflectionUtil.getTaggedPropertyValue( object, "Request" );
         if (propVal != null) {
            return true;
         }
         propVal = ReflectionUtil.getTaggedPropertyValue( object, "RequestSource" );
         if (propVal != null) {
            return true;
         }
         return false;
      }

      /**
       * Clear all references.
       */
      public function clear():void {
         requestor = null;
         request = null;
         result = null;
         error = null;
         resultInfo = null;
      }
   }

}